package fx.utils;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * <desc>
 * md5加密帮助类
 * </desc>
 *
 * @createDate
 */
public class Md5EncryptUtil {

    /**
     * <desc>
     * MD5加密
     * </desc>
     *
     * @param str
     * @return MD5加密字符串
     * @author Jiaqi.X
     * @createDate 2017/09/15
     */
    public static String md5(String str) {
        return DigestUtils.md5Hex(str);
    }


    /**
     * <desc>
     * APP端校验参数及签名串MD5值
     * </desc>
     *
     * @param params
     * @param appSign
     * @param MOBILE_MD5_KEY
     * @return
     */
    public static boolean checkAppSign(Map<String, String> params, String appSign, String MOBILE_MD5_KEY) {
        if (params == null || StringUtils.isBlank(appSign)) {
            return false;
        }
        StringBuffer stringA = new StringBuffer();
        List<Map.Entry<String, String>> mappingList = new ArrayList<Map.Entry<String, String>>(params.entrySet());
        Collections.sort(mappingList, new Comparator<Map.Entry<String, String>>() {
            @Override
            public int compare(Map.Entry<String, String> mappingF, Map.Entry<String, String> mappingS) {
                return mappingF.getKey().toLowerCase().compareTo(mappingS.getKey().toLowerCase());
            }
        });
        String createTimeValue = "", languageValue = "";
        for (Map.Entry<String, String> mapping : mappingList) {
            if ("createTime".equals(mapping.getKey())) {
                createTimeValue = mapping.getValue();
            } else if ("language".equals(mapping.getKey())) {
                languageValue = mapping.getValue();
            } else {
                stringA.append(mapping.getKey());
            }
        }
        stringA.append(languageValue);
        stringA.append(createTimeValue);

        String result = stringA.append(MOBILE_MD5_KEY).toString();
//        System.out.println("result:"+result);
        result = md5(result);
//        System.out.println("appSign:"+appSign);
        return result.equals(appSign);
    }

    /**
     * <desc>
     * APP端校验参数及签名串MD5值
     * </desc>
     *
     * @param params
     * @param appSign
     * @param MOBILE_MD5_KEY
     * @return
     */
    public static boolean checkAppSignValue(Map<String, String> params, String appSign, String MOBILE_MD5_KEY) {
        if (params == null || StringUtils.isBlank(appSign)) {
            return false;
        }
        StringBuffer stringA = new StringBuffer();
        List<Map.Entry<String, String>> mappingList = new ArrayList<Map.Entry<String, String>>(params.entrySet());
        Collections.sort(mappingList, new Comparator<Map.Entry<String, String>>() {
            @Override
            public int compare(Map.Entry<String, String> mappingF, Map.Entry<String, String> mappingS) {
                return mappingF.getKey().toLowerCase().compareTo(mappingS.getKey().toLowerCase());
            }
        });
        String createTimeValue = "", languageValue = "";
        for (Map.Entry<String, String> mapping : mappingList) {
            if ("createTime".equals(mapping.getKey())) {
                createTimeValue = mapping.getValue();
            } else if ("language".equals(mapping.getKey())) {
                languageValue = mapping.getValue();
            } else {
                stringA.append(mapping.getValue() == null ? "" : mapping.getValue());
            }
        }
        stringA.append(languageValue);
        stringA.append(createTimeValue);

        String result = stringA.append(MOBILE_MD5_KEY).toString();
//        System.out.println("result:"+result);
        result = md5(result);

//        System.out.println("appSign:"+appSign);
        return result.equals(appSign);

        // 兼容小程序未更新验签
//        return result.equals(appSign) || checkAppSign(params, appSign, MOBILE_MD5_KEY);
    }

    /**
     * <desc>
     * APP端校验参数及签名串MD5值
     * </desc>
     *
     * @param params         验签参数集
     * @param appSign        app端验签结果
     * @param MOBILE_MD5_KEY 验签key
     * @param mark           预留参数
     * @return
     */
    public static boolean checkAppSignValue(Map<String, Object> params, String appSign, String MOBILE_MD5_KEY, String mark) {
        if (params == null || StringUtils.isBlank(appSign)) {
            return false;
        }
        StringBuffer stringA = new StringBuffer();
        List<Map.Entry<String, Object>> mappingList = new ArrayList<Map.Entry<String, Object>>(params.entrySet());
        Collections.sort(mappingList, new Comparator<Map.Entry<String, Object>>() {
            @Override
            public int compare(Map.Entry<String, Object> mappingF, Map.Entry<String, Object> mappingS) {
                return mappingF.getKey().toLowerCase().compareTo(mappingS.getKey().toLowerCase());
            }
        });
        String createTimeValue = "", languageValue = "";
        for (Map.Entry<String, Object> mapping : mappingList) {
            if ("createTime".equals(mapping.getKey())) {
                createTimeValue = mapping.getValue() == null ? "" : mapping.getValue().toString();
            } else if ("language".equals(mapping.getKey())) {
                languageValue = mapping.getValue() == null ? "" : mapping.getValue().toString();
            } else {
                stringA.append(mapping.getValue() == null ? "" : mapping.getValue().toString());
            }
        }
        stringA.append(languageValue);
        stringA.append(createTimeValue);

        String result = stringA.append(MOBILE_MD5_KEY).toString();
        result = md5(result);
//        System.out.println("result:" + result);
//        System.out.println("appSign:" + appSign);
        return result.equals(appSign);
    }

    /**
     * <desc>
     * 云设备计算MD5
     * </desc>
     *
     * @param params
     * @param appsecret
     * @return
     */
    public static String cloudDeviceMd5(Map<String, Object> params, String createTime, String appsecret) {
        if (params == null || StringUtils.isBlank(appsecret)) {
            return null;
        }
        StringBuffer stringA = new StringBuffer();
        List<Map.Entry<String, Object>> mappingList = new ArrayList<Map.Entry<String, Object>>(params.entrySet());
        Collections.sort(mappingList, new Comparator<Map.Entry<String, Object>>() {
            @Override
            public int compare(Map.Entry<String, Object> mappingF, Map.Entry<String, Object> mappingS) {
                return mappingF.getKey().toLowerCase().compareTo(mappingS.getKey().toLowerCase());
            }
        });
        for (Map.Entry<String, Object> mapping : mappingList) {
            stringA.append(mapping.getValue() == null ? "" : mapping.getValue());
        }
        stringA.append(createTime);
        return md5(stringA.append(appsecret).toString());
    }

    /**
     * <desc>
     * 云电梯SDK校验参数及签名串MD5值
     * </desc>
     *
     * @param params
     * @param appSign
     * @param MOBILE_MD5_KEY
     * @return
     */
    public static boolean checkCloudTalkSDKSign(Map<String, Object> params, String appSign, String MOBILE_MD5_KEY) {
        if (params == null || StringUtils.isBlank(appSign)) {
            return false;
        }
        StringBuffer stringA = new StringBuffer();
        List<Map.Entry<String, Object>> mappingList = new ArrayList<Map.Entry<String, Object>>(params.entrySet());
        Collections.sort(mappingList, new Comparator<Map.Entry<String, Object>>() {
            @Override
            public int compare(Map.Entry<String, Object> mappingF, Map.Entry<String, Object> mappingS) {
                return mappingF.getKey().toLowerCase().compareTo(mappingS.getKey().toLowerCase());
            }
        });
        String createTimeValue = "";
        for (Map.Entry<String, Object> mapping : mappingList) {
            if ("createTime".equals(mapping.getKey())) {
                createTimeValue = mapping.getValue().toString();
            } else {
                stringA.append(mapping.getValue() == null ? "" : mapping.getValue().toString());
            }
        }
        stringA.append(createTimeValue);
        String result = stringA.append(MOBILE_MD5_KEY).toString();
        result = md5(result);
        return result.equals(appSign);
    }

    /**
     * <desc>
     * sdkV2版本验签方法
     * </desc>
     *
     * @param params
     * @param appSign
     * @param appsecret
     * @return
     */
    public static boolean checkSDKV2Sign(Map<String, Object> params, String appSign, String requestId, String timestamp, String appsecret) {
        if (params == null || StringUtils.isBlank(appSign)) {
            return false;
        }
        StringBuffer stringA = new StringBuffer();
        List<Map.Entry<String, Object>> mappingList = new ArrayList<Map.Entry<String, Object>>(params.entrySet());
        Collections.sort(mappingList, new Comparator<Map.Entry<String, Object>>() {
            @Override
            public int compare(Map.Entry<String, Object> mappingF, Map.Entry<String, Object> mappingS) {
                return mappingF.getKey().toLowerCase().compareTo(mappingS.getKey().toLowerCase());
            }
        });
        for (Map.Entry<String, Object> mapping : mappingList) {
            stringA.append(mapping.getValue() == null ? "" : mapping.getValue().toString());
        }
        stringA.append(requestId);
        stringA.append(timestamp);
        stringA.append(appsecret);
        String result = md5(stringA.toString());
        return result.equals(appSign);
    }

    /**
     * <desc>
     * sdkv2计算MD5
     * </desc>
     *
     * @param params
     * @param appsecret
     * @return
     */
    public static String getSDKV2Md5(Map<String, Object> params, String requestId, String timestamp, String appsecret) {
        if (params == null || StringUtils.isBlank(appsecret)) {
            return null;
        }
        StringBuffer stringA = new StringBuffer();
        List<Map.Entry<String, Object>> mappingList = new ArrayList<Map.Entry<String, Object>>(params.entrySet());
        Collections.sort(mappingList, new Comparator<Map.Entry<String, Object>>() {
            @Override
            public int compare(Map.Entry<String, Object> mappingF, Map.Entry<String, Object> mappingS) {
                return mappingF.getKey().toLowerCase().compareTo(mappingS.getKey().toLowerCase());
            }
        });
        for (Map.Entry<String, Object> mapping : mappingList) {
            stringA.append(mapping.getValue() == null ? "" : mapping.getValue());
        }
        stringA.append(requestId);
        stringA.append(timestamp);
        stringA.append(appsecret);
        return md5(stringA.toString());
    }

    /**
     * <desc>
     * sdkV3版本验签方法
     * </desc>
     *
     * @param params
     * @param appSign
     * @param appsecret
     * @return
     */
    public static boolean checkSDKV3Sign(Map<String, Object> params, String appsecret, String appSign, String... values) {
        String result = getSDKV3Sign(params, appsecret, values);
        if (StringUtils.isEmpty(result)) {
            return false;
        }
        return result.equals(appSign);
    }


    /**
     * <desc>
     * sdkv3计算sign
     * </desc>
     *
     * @param params
     * @param appsecret
     * @return
     */
    public static String getSDKV3Sign(Map<String, Object> params, String appsecret, String... values) {
        if (params == null || StringUtils.isBlank(appsecret)) {
            return null;
        }
        StringBuffer stringA = new StringBuffer();
        List<Map.Entry<String, Object>> mappingList = new ArrayList<Map.Entry<String, Object>>(params.entrySet());
        Collections.sort(mappingList, new Comparator<Map.Entry<String, Object>>() {
            @Override
            public int compare(Map.Entry<String, Object> mappingF, Map.Entry<String, Object> mappingS) {
                return mappingF.getKey().toLowerCase().compareTo(mappingS.getKey().toLowerCase());
            }
        });
        for (Map.Entry<String, Object> mapping : mappingList) {
            stringA.append(mapping.getValue() == null ? "" : mapping.getValue());
        }
        for (String value : values) {
            stringA.append(value);
        }
        stringA.append(appsecret);
        return md5(stringA.toString());
    }

    /**
     * <desc>
     * 将userId转化为8位的HEX(MD5加密后截取奇数位)
     * <desc/>
     *
     * @param source 待加密的MD5数据
     * @return 生成的HEX
     * @author Biao.R
     * @createDate 2018/1/24
     */
    public static String offLineUserIdHandler(String source) {
        if (StringUtils.isEmpty(source)) {
            return "";
        }
        if (source.length() <= 8) {
            return source;
        }
        StringBuffer sb = new StringBuffer(8);
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] array = md.digest(source.getBytes("utf-8"));
            //遍历获取4到12位，得到MD5的16位数，并取其中的奇数位
            for (int i = 4; i < 12; i++) {
                String substring = Integer.toHexString((array[i] & 0xFF) | 0x100).toUpperCase().substring(1, 3);
                sb.append(substring.charAt(0));
            }
        } catch (Exception e) {
            return null;
        }
        return sb.toString();
    }

    /**
     * <desc>
     * md5加密
     * </desc>
     *
     * @param psd
     * @param salt
     * @return
     */
    public static String enWithSalt(String psd, String salt) {
        try {
            StringBuffer stingBuffer = new StringBuffer();
            // 1.指定加密算法
            MessageDigest digest = MessageDigest.getInstance("MD5");
            // 2.将需要加密的字符串转化成byte类型的数据，然后进行哈希过程
            byte[] bs = digest.digest((psd + salt).getBytes());
            // 3.遍历bs,让其生成32位字符串，固定写法
            // 4.拼接字符串
            for (byte b : bs) {
                int i = b & 0xff;
                String hexString = Integer.toHexString(i);
                if (hexString.length() < 2) {
                    hexString = "0" + hexString;
                }
                stingBuffer.append(hexString);
            }
            return stingBuffer.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * <desc>
     * 微信支付签名算法
     * </desc>
     *
     * @param map 要参与签名的数据对象
     * @param key 参与加密的key
     * @return 签名
     * @throws IllegalAccessException
     * @author Jiaqi.X
     * @createDate 2018/04/18
     */
    public static String getWechatSign(Map<Object, Object> map, String key) {
        ArrayList<String> list = new ArrayList<String>();
        for (Map.Entry<Object, Object> entry : map.entrySet()) {
            if (entry.getValue() != "") {
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + key;
        result = md5(result).toUpperCase();
        return result;
    }

}
